<template>
    <div class="pagination-table">
        <ConfigTable v-bind="props" v-on="listenObj"
            ref="configTableRef" @sort-change="sortChange" @filter-change="handleFilterChange">
            <!-- 循环使用后创建 -->
            <template #[item] v-for="item in slotsArray">
                <slot :name="item">
                    
                </slot>
            </template>
        </ConfigTable>
        <el-divider style="margin: 20px 0 10px;"/>
        <div class="pagination-wrapper">
            <div class="total">
                &nbsp;共{{total}}条&nbsp;数据
            </div>
            <el-pagination class="pagination" 
                v-if="needPaination"
                background 
                size="default"
                :page-sizes="props.pageSizeTypes"
                :page-size="props.pageSize"
                :total="props.total"
                :current-page="props.pageNum"
                :layout="props.layout"
                @size-change="onSizeChange"
                @current-change="onCurrentChange"
            />
        </div>
    </div>
</template>

<script lang="ts" setup>
// 可配置表格加上分页功能
import ConfigTable, { ConfigTableProps, } from "@/components/Table/configTable.vue";
import { deepCopy } from '@/utils/index.js';
import { computed, onMounted, ref, useSlots } from "vue";
import { tableEvents, TableEventTypes } from "./index";

// 禁用属性透传
defineOptions({
    inheritAttrs: false
});

export type PaginationTableProps = {
    pageSize?: number;
    pageNum?: number;
    pageSizeTypes?: number[];
    total?: number;
    layout?: string;
    needPaination?:boolean, // 是否需要分页组件
}

// 本组件的接受到的所有插槽(其实就是函数)
const slots = useSlots();
const slotsArray = computed(()=>{
    return Object.keys(slots);
});

const props = withDefaults(defineProps<PaginationTableProps&ConfigTableProps>(), {
    pageSize: 10,
    pageSizeTypes: ()=>[10, 30, 50, 100],
    total: 0,
    pageNum: 1,
    layout: 'sizes, prev, pager, next, jumper',
    needPaination: true,

    // 复制自ConfigTable的默认配置；defineProps会将boolean默认值推导为false，所以这里需要手动设置为true（真坑）
    columns: () => [],
    data: () => [],
    height: 'auto',
    size: 'large',
    fit: true,
    border: true,
    emptyText: '暂无数据',
    showHeader: true,
    defaultColumnWidth: 150,
    scrollbarAlwaysOn: true,
    rowKey: 'id',
    selectable: true,
    selectColumnWidth: 50,
    selectableCall: () => true,
    loading: false,
    sortType: 'backend',
});


const configTableRef = ref<InstanceType<typeof ConfigTable>>();
export type QueryType = {
    filter: Record<string, any>,
    search: Record<string, any>,
    page: {
        pageSize: number,
        pageNum: number,
    },
    sort: {
        field: string,
        order: string,
    }
}

// 查询条件
const query: QueryType = {
    filter: {},
    search: {},
    page: {
        pageSize: 10,
        pageNum: 1,
    },
    sort: {
        field: "",
        order: ""
    }
}


// defineEmits/definePeops 是编译时宏函数而非运行时函数，所以不能用变量，因为会报错，所以直接写死
const emits = defineEmits([
    // 可配置表格的事件
    'selection-change',
    'cell-click',
    'cell-dblclick',
    'row-click',
    'row-contextmenu',
    'row-dblclick',
    'header-click',
    'header-contextmenu',
    'sort-change',
    'filter-change',
    'current-change',
    'header-dragend',
    'expand-change',

    // 分页表格事件
    'fetchData',
]);

// 把table的事件冒泡出去
const emitEvent = (event: TableEventTypes, ...args: any[]) => {
    emits(event, ...args);
}
// 监听事件对象，直接原样抛出
const listenObj: any = tableEvents.reduce((obj: Record<string, any>, key: TableEventTypes) => {
    // 需要被特殊处理的事件，不能原样弹出
    if(['filter-change', 'sort-change'].includes(key)){
        return obj;
    }
    obj[key] = (...args: any[]) => emitEvent(key, ...args);
    return obj;
}, {});



function onSizeChange(pageSize:number) {
    query.page.pageSize = pageSize;
    getData(true);
}

function onCurrentChange(pageNum:number) {
    query.page.pageNum = pageNum;
    getData();
}

const sortChange = (data: any) => {
    getData();
}

const handleFilterChange = (newFilters: any)=>{
    getData();
}

// 处理查询参数，将排序、筛选、分页等参数处理到query中，然后在请求接口时，将query参数带到接口中，这样后端就能根据query参数来进行排序、筛选、分页等操作
const handleQueryParams = (reset=false) => {
    if(reset){
        query.page.pageNum = 1;
    }

    // 直接获取列配置数组
    const columns = configTableRef.value?.getColumns();
    if(!columns){
        console.warn("列配置为空，请检查");
        return false;
    }

    for(let columnItem of columns){
        if(columnItem.sortable&&columnItem.order){
            query.sort.field = columnItem.rawColumnKey;
            query.sort.order = columnItem.order;
        }

        if(columnItem.filterable&&columnItem.filteredValue.length){
            query.filter[columnItem.rawColumnKey] = deepCopy(columnItem.filteredValue);
        }
    }

    return true;
}

const getData = (reset=false) => {
    if(!handleQueryParams(reset)){
        return;
    }
    emits('fetchData', query);
}

defineExpose({
    getTableInstance: () => configTableRef.value,
    setSerchParams: (params: any) => {
        query.search = params;
        getData(true);
    },
    getQuery: () => query,
    getData,
});

onMounted(() => {
    getData();
});
</script>

<style lang="scss" scoped>
.pagination-table{
    .pagination-wrapper{
        display: flex;
        justify-content: space-between;
        align-items: center;
        column-gap: 20px;
        font-size: 15px;
        .total{
            color: #999;
        }
        .pagination{

        }
    }
}
</style>